﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Djs.Tools.Tresor.Forms
{
    public partial class CreateKeyForm : Djs.Tools.Tresor.Gui.FillForm
    {
        public CreateKeyForm()
        {
            this.KeyFileName = @"C:\tresor.key";
            InitializeComponent();
            this.Fms.RegisterControl(this._Info);
            this.InitKeyImage();
            this.InitKeyData();

            this.DialogResult = System.Windows.Forms.DialogResult.None;
        }
        private void InitKeyImage()
        {
            this.KeyImage = new Gui.TransparentPictureBox();
            this.KeyImage.Transparency = 0.03f;
            this.KeyImage.Image = Properties.Resources.SecureKey;
            this.KeyImage.Parent = this;

            this.KeyInfo = new Gui.KeyInfo();
            this.KeyInfo.Font = SystemFonts.DefaultFont;
            this.KeyInfo.ForeColor = SystemColors.ControlText;
            this.KeyInfo.Strong = 0f;
            this.KeyInfo.Parent = this;

            this._Info.Text = GetInfoText();

            this.KeyImageSetBounds();
        }
        /// <summary>
        /// Jméno souboru, do kterého se má uložit klíč k trezoru.
        /// </summary>
        public string KeyFileName { get; set; }
        private Gui.TransparentPictureBox KeyImage;
        private Gui.KeyInfo KeyInfo;
        private Random Rand;
        private string GetInfoText()
        {
            string text = @"Toto okno generuje klíč k trezoru.
Každé spuštění okna generuje nový unikátní klíč.

Pohybujte myší nad oknem, tím přidáte do klíče další náhodný faktor.

Sledujte informaci o navyšování síly klíče, která vyjadřuje jeho náhodnost a neopakovatelnost.

Jakmile dosáhnete požadované síly klíče, uložte jej kliknutím na tlačítko vpravo dole.";

            return text;
        }
        private void KeyImageSetBounds()
        {
            if (this._SaveKeyBtn == null) return;

            Rectangle formBounds = this.ClientRectangle; // .ClientSize;
            Point end = new Point(formBounds.Right - 6, this._SaveKeyBtn.Top - 6);
            if (this.KeyInfo != null)
            {
                this.KeyInfo.Bounds = new Rectangle(end.X - 350, end.Y - 24, 350, 20);
                end.Y = this.KeyInfo.Bounds.Top - 3;
            }
            if (this.KeyImage != null)
            {
                this.KeyImage.Bounds = new Rectangle(end.X - 350, end.Y - 200, 350, 200);
            }
        }
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            this.KeyImageSetBounds();
        }

        private void _Timer_Tick(object sender, EventArgs e)
        {
            if (!this.TimerTickBlock)
            {
                this._Timer.Enabled = false;
                this.TimerTickBlock = true;
                this.AddKeyList();
                this.TimerTickBlock = false;
                int speed = (this.KeyListValues < 100 ? 25 : (this.KeyListValues < 200 ? 20 : (this.KeyListValues < 400 ? 15 : (this.KeyListValues < 600 ? 10 : 8))));
                this._Timer.Interval = this.Rand.Next(speed, 4 * speed);
                this._Timer.Enabled = true;
            }
        }
        private void InitKeyData()
        {
            this.Rand = new Random();

            this.KeyList = new int[LENGTH];
            this.KeyListPointer = 0;
            this.KeyListValues = 0;

            for (int x = 0; x < LENGTH; x++)
                this.KeyList[x] = this.GetOneKey((x + 17) * 23, 1594836 - (x * 7));

            this._Timer.Interval = 40;
            this.MouseMove += new MouseEventHandler(_MouseMove);
            this._Info.MouseMove += new MouseEventHandler(_MouseMove);
        }

        void _MouseMove(object sender, MouseEventArgs e)
        {
            if (!this.TimerTickBlock)
            {
                this.TimerTickBlock = true;
                this.AddKeyList();
                this.TimerTickBlock = false;
            }
        }
        private int[] KeyList;
        private int KeyListValues;
        private int KeyListPointer;
        private bool TimerTickBlock;
        private const int LENGTH = 0x04000;
        private void AddKeyList()
        {
            Point point = Control.MousePosition;
            int value = GetOneKey(point.X, point.Y);
        
            int scan = this.KeyListPointer;
            for (int i = 0; i < 5; i++)
            {
                scan = GetNextKeyIndex(scan, -1);
                if (this.KeyList[scan] == value)
                    return;
            }

            this.KeyList[this.KeyListPointer] = value;
            this.KeyListIncrement();
            int values = this.KeyListValues;

            if (values <= 4096)
            {
                this._StatusInfo.Text = "Délka klíče: " + values.ToString();
                this._StatusBar.Refresh();
            }

            double strong = (double)values / 4096d;
            strong = (strong < 0d ? 0d : (strong > 1d ? 1d : strong));

            this.KeyInfo.Strong = (float)(0.01d + 0.99d * strong);

            float transparency = (float)(0.5d - 0.5d * Math.Cos(Math.PI * strong));            // cos(0) = 1, cos(90°) = 0, cos(180°) = -1;  Math.PI = 180°: převedu na křivku 0 => 1
            this.KeyImage.Transparency = transparency;

        }
        private int GetOneKey(int x, int y)
        {
            int rand = (int)(this.Rand.Next(0x010000, 0x01FFFF) & 0x00FFFF);
            int time = (int)((DateTime.Now.Ticks & 0x00FFFF) ^ ((DateTime.Now.Ticks >> 20) & 0x00FFFF));
            int coor = (int)(x ^ x);
            return ((rand ^ time ^ coor) & 0x00FFFF);
        }
        private void KeyListIncrement()
        {
            this.KeyListPointer = this.GetNextKeyIndex(this.KeyListPointer, 1);
            this.KeyListValues++;
        }
        private int GetNextKeyIndex(int index, int step)
        {
            int result = index + step;
            if (result >= LENGTH) result = result % LENGTH;
            while (result < 0) result = result + LENGTH;
            return result;
        }

        private void _SaveKeyBtn_Click(object sender, EventArgs e)
        {
            string fileName = this.KeyFileName;
            if (String.IsNullOrEmpty(fileName))
            {
                MessageBox.Show("Není určen soubor do kterého se má uložit klíč.", "Klíč", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            byte[] buffer = null;
            using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
            {
                for (int i = 0; i < LENGTH; i++)
                {
                    ms.WriteByte((byte)(this.KeyList[i] & 0x00FF));
                    ms.WriteByte((byte)((this.KeyList[i] & 0xFF00) >> 8));
                }
                buffer = ms.ToArray();
            }

            System.IO.File.WriteAllBytes(fileName, buffer);

            if (System.IO.File.Exists(fileName))
            {
                this.DialogResult = System.Windows.Forms.DialogResult.OK;
                this.Close();
            }
            else
            {
                MessageBox.Show("Klíč se nepodařilo uložit do souboru " + fileName, "Klíč", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }
        }
    }
}
